package jinyilw.tools.net;

import jinyilw.common.OSTools;
import jinyilw.common.log.LogTools;
import jinyilw.tools.net.dev.TCPClient;
import jinyilw.tools.net.dev.TCPServer;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;

public class NetTools
{
	public static boolean debug = true;
	private static final String localIP = "127.0.0.1";
	private static InetAddress localAddress;
	private static String hostIP;
	private NetTools()
	{
	}

	public static TCPServer createTCPServer(TCPParameter parameter)
	{
		if (parameter == null)
			return null;
		return createTCPServer(parameter.port);
	}

	public static TCPServer createTCPServer(int port)
	{
		try
		{
			return new TCPServer(port);
		} catch (IOException e)
		{
			LogTools.debug("启动TCP服务器失败!", e);
			return null;
		}
	}

	public static TCPClient createTCPClient(TCPParameter parameter)
	{
		if (parameter == null)
			return null;
		return createTCPClient(parameter.serverIP, parameter.port);
	}

	public static TCPClient createTCPClient(String serverIP, int port)
	{
		TCPClient client;
		try
		{
			client = new TCPClient(serverIP, port);
		} catch (IOException e)
		{
			LogTools.debug("TCP客户端连接服务器失败!", e);
			client = null;
		}
		return client;
	}

	public static String getHostIP()
	{
		if (hostIP == null || hostIP.equals("未启用"))
		{
			InetAddress ip = getHostInetAddress();
			if (ip != null)
				hostIP = ip.getHostAddress();
			else
				hostIP = "未启用";
		}
		return hostIP;
	}

	private static InetAddress getHostInetAddress()
	{
		try
		{
			if (OSTools.isWindows())
				return InetAddress.getLocalHost();
			Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface
					.getNetworkInterfaces();
			InetAddress ip;
			while (allNetInterfaces.hasMoreElements())
			{
				NetworkInterface netInterface = allNetInterfaces.nextElement();
				if (netInterface.isLoopback() || netInterface.isVirtual()
						|| !netInterface.isUp())
				{
					continue;
				} else
				{
					Enumeration<InetAddress> addresses = netInterface
							.getInetAddresses();
					while (addresses.hasMoreElements())
					{
						ip = addresses.nextElement();
						if (ip instanceof Inet4Address)
							return ip;
					}
				}
			}
		} catch (Exception e)
		{
			System.err.println("IP地址获取失败:" + e);
		}
		return null;
	}

	private static InetAddress getLocalInetAddress()
	{
		if (localAddress == null)
			try
			{
				localAddress = InetAddress.getByName(localIP);
			} catch (UnknownHostException e)
			{
				e.printStackTrace();
			}
		return localAddress;
	}

	public static synchronized int getLocalAvailablePort()
	{
		int port = (int) (Math.random() * 20000 + 2000);
		while (isPortUsing(getLocalInetAddress(), port))
			port = (int) (Math.random() * 20000 + 2000);
		return port;
	}

	/**
	 * 查看本机某端口是否被占用
	 */
	public static boolean isLocalPortUsing(int port)
	{
		return isPortUsing(getLocalInetAddress(), port);
	}

	/**
	 * 根据IP和端口号，查询其是否被占用
	 */
	public static boolean isPortUsing(InetAddress address, int port)
	{
		try
		{
			Socket socket = new Socket(address, port);
			socket.close();
			return true;
		} catch (IOException e)
		{
			return false;
		}
	}

	/**
	 * 发get请求，获取文本
	 */
	public static String sendGetRequest(String getUrl)
	{
		StringBuilder sb = new StringBuilder();
		InputStreamReader isr;
		BufferedReader br;
		try
		{
			URL url = new URL(getUrl);
			URLConnection urlConnection = url.openConnection();
			urlConnection.setAllowUserInteraction(false);
			isr = new InputStreamReader(url.openStream(),
					StandardCharsets.UTF_8);
			br = new BufferedReader(isr);
			String line;
			while ((line = br.readLine()) != null)
				sb.append(line);
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		return sb.toString();
	}

	/**
	 * 从网络Url中下载文件
	 */
	public static void downLoadFromUrl(String urlStr, String fileName,
			String savePath) throws IOException
	{
		URL url = new URL(urlStr);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(3000);
		// 防止屏蔽程序抓取而返回403错误
		conn.setRequestProperty("User-Agent",
				"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

		InputStream inputStream = conn.getInputStream();
		byte[] getData = getBytesFromStream(inputStream);

		File saveDir = new File(savePath);
		if (!saveDir.exists())
			saveDir.mkdir();

		File file = new File(saveDir, fileName);
		FileOutputStream fos = new FileOutputStream(file);
		fos.write(getData);
		fos.close();
		inputStream.close();

		LogTools.info(url + " download success");
	}

	public static byte[] getBytesFromStream(InputStream inputStream)
			throws IOException
	{
		byte[] buffer = new byte[1024];
		int len = 0;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		while ((len = inputStream.read(buffer)) != -1)
			bos.write(buffer, 0, len);
		bos.close();
		return bos.toByteArray();
	}

	public static String getStringFromStream(InputStream in, Charset cs)
			throws IOException
	{
		StringBuilder sb = new StringBuilder();
		BufferedReader reader = new BufferedReader(
				new InputStreamReader(in, cs));
		String line;
		while ((line = reader.readLine()) != null)
			sb.append(line);
		return sb.toString();
	}
}
